package com.ctshk.rpc.order.goods.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.constant.ElasticSearchConstant;
import com.ctshk.common.constant.RedisConstants;
import com.ctshk.common.dto.Result;
import com.ctshk.common.elasticsearch.config.ElasticSearchConfiguration;
import com.ctshk.common.enums.Currency;
import com.ctshk.common.enums.IsDeletedCode;
import com.ctshk.common.enums.SystemBusinessType;
import com.ctshk.common.enums.SystemError;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.rpc.cms.dto.BannerPositionListDTO;
import com.ctshk.rpc.cms.service.IBannerPositionService;
import com.ctshk.rpc.goods.service.ICommodityService;
import com.ctshk.rpc.order.goods.dto.CommodityInfoListDTO;
import com.ctshk.rpc.order.goods.dto.*;
import com.ctshk.rpc.order.goods.dto.resp.*;
import com.ctshk.rpc.order.goods.entity.*;
import com.ctshk.rpc.order.goods.mapper.*;
import com.ctshk.rpc.order.goods.req.RegionalFreightReq;
import com.ctshk.rpc.order.goods.service.ICommodityClassificationService;
import com.ctshk.rpc.order.goods.service.ICommodityHomeService;
import com.ctshk.rpc.user.req.UserFootPointReq;
import com.ctshk.rpc.user.service.IUserFootPointService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * TODO
 * 商品首页 服务实现
 *
 * @author huangxiansheng
 * @date 2021/5/19 1:07 下午
 */
@Slf4j
@DubboService
public class ICommodityHomeServiceImpl extends ServiceImpl<ICommodityHomeMapper, Commodity> implements ICommodityHomeService {

    @Autowired
    ICommodityHomeMapper iCommodityHomeMapper;

    @DubboReference
    private IBannerPositionService bannerPositionService;

    @DubboReference
    private ICommodityHomeService iCommodityHomeService;

    @Autowired
    CommodityAttributeMapper commodityAttributeMapper;  //商品属性

    @Autowired
    CommodityCostMapper commodityCostMapper;  // 商品成本信息

    @Autowired
    private CommodityLogMapper commodityLogMapper; // 商品操作日志mapper

    @Autowired
    private CommodityMapper commodityMapper; // 商品mapper

    @Autowired
    private CommodityKeyWordMapper keyWordMapper; // 商品關鍵字mapper

    @Autowired
    private CommodityLabelMapper labelMapper; // 商品標籤mapper

    @Autowired
    private CommodityRecommendMapper recommendMapper; // 商品推薦mapper

    @Autowired
    private CommodityFileMapper fileMapper; // 商品文件mapper

    @Autowired
    private CommodityAttributeMapper attributeMapper; // 商品属性mapper

    @Autowired
    private CommodityCostMapper costMapper; // 商品成本mapper

    @Autowired
    private CommodityCostAttributeMapper costAttributeMapper; // 商品成本属性mapper

    @Autowired
    private ShoppingSpecialMapper shoppingSpecialMapper; // 商品专题Mapper

    @Autowired
    private CommoditySalesAreaMapper salesAreaMapper; // 商品销售区域mapper

    @Autowired
    private ShoppingCommoditySpecificationsNameMapper specificationsNameMapper; // 商城商品规格名称mapper

    @Autowired
    private ShoppingCommoditySpecificationsMapper specificationsMapper; // 商城商品规格mapper

    @Autowired
    private ShoppingCommoditySpecificationsAttributeMapper specificationsAttributeMapper; // 商城商品规格屬性mapper

    @Autowired
    private CommodityFileMapper commodityFileMapper;

    @Autowired
    private CommodityLabelMapper commodityLabelMapper;

    @Autowired
    private CommodityClassificationMapper commodityClassificationMapper;

    @Autowired
    private ElasticSearchCommodityMapper elasticSearchCommodityMapper;  // 商品分类es

    @Autowired
    private RedisTemplate<String, Object> redisTemplate; // redis操作类

    @Autowired
    private RestHighLevelClient restHighLevelClient; // es操作类

    @Autowired
    private CommodityCostAttributeMapper commodityCostAttributeMapper; // 商品成本属性

    @Autowired
    private CommoditySalesAreaMapper commoditySalesAreaMapper; // 商品区域

    @Autowired
    CommodityKeyWordMapper commodityKeyWordMapper; //商品关键字

    @DubboReference
    private ICommodityClassificationService classificationService;

    @DubboReference
    private ICommodityService commodityService;

    @Autowired
    private ShoppingSpecialCommodityMapper shoppingSpecialCommodityMapper;

    @Autowired
    private RegionalFreightMapper regionalFreightMapper;

    @Autowired
    CommodityHotWordMapper commodityHotWordMapper;

    @DubboReference
    private IUserFootPointService userFootPointService;

    /**
     * 上架商品信息到es
     *
     * @return
     */
    private void upClassificationEs(List<CommodityInfoListDTO> commodityAllList) {
        elasticSearchCommodityMapper.deleteAll();
        elasticSearchCommodityMapper.saveAll(commodityAllList);
    }

    /**
     * PC端 商城专题列表
     */
    @Override
    public Result<List<ShoppingSpecialPageDTO>> getShoppingSpecial() {
        if (!hasKey(RedisConstants.GOODS_HOME_SPECIAL)) {
            Boolean flag = false;
            if (!flag) {
                return Result.failed(SystemError.TOUR_30013);
            }
        }
        String str = (String) redisTemplate.opsForValue().get(RedisConstants.GOODS_HOME_SPECIAL);
        List<ShoppingSpecialPageDTO> data = JSONArray.parseArray(str, ShoppingSpecialPageDTO.class);
        for (ShoppingSpecialPageDTO specialPageDTO : data) {
            List<ShoppingSpecialPageUrlDTO> list = JSON.parseArray(specialPageDTO.getSpecialPictureUrl(), ShoppingSpecialPageUrlDTO.class);
            specialPageDTO.setSpecialPictureUrl(list.get(0).getUrl());
        }
        return Result.success(data);
    }

    /**
     * redis中是否存在key
     *
     * @param key
     * @return
     */
    private boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 商城级联分类获取
     *
     * @return
     */
    @Override
    public Result<List<CommodityClassificationAllLevelListDTO>> getClassification() {
        log.info("【中旅商城--C端--级联分类获取--start】");
        if (!hasKey(RedisConstants.GOODS_HOME_CLASSIFICATION_ALL)) {
            // 查询父子级分类名称集合列表
            List<CommodityClassificationAllLevelListDTO> classificationByAllLevel = classificationService.findClassificationByAllLevel(null);
            if (org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty(classificationByAllLevel)) {
                log.info("【查询父子级分类名称集合列表，数据返参为:{}】", JSON.toJSONString(classificationByAllLevel));
                Collections.sort(classificationByAllLevel, new Comparator<CommodityClassificationAllLevelListDTO>() {
                    @Override
                    public int compare(CommodityClassificationAllLevelListDTO o1, CommodityClassificationAllLevelListDTO o2) {
                        if (null != o1.getSort() && null != o2.getSort()) {
                            if (o1.getSort() > o2.getSort()) {
                                return 1;
                            }
                            if (o1.getSort() == o2.getSort()) {
                                return 0;
                            }
                        }
                        return -1;
                    }
                });
            }
            redisTemplate.delete(RedisConstants.GOODS_HOME_CLASSIFICATION_ALL);
            redisTemplate.opsForValue().set(RedisConstants.GOODS_HOME_CLASSIFICATION_ALL, JSON.toJSONString(classificationByAllLevel));
            return Result.success(classificationByAllLevel);
        }
        String str = (String) redisTemplate.opsForValue().get(RedisConstants.GOODS_HOME_CLASSIFICATION_ALL);
        log.info("【中旅商城--C端--级联分类获取--缓存数据读取】，返参为:{}", str);
        List<CommodityClassificationAllLevelListDTO> allLevelListDTOS = JSON.parseObject(str, new TypeReference<List<CommodityClassificationAllLevelListDTO>>() {
        });
        allLevelListDTOS = allLevelListDTOS.stream().filter(cf -> {
            return cf.getLevelTwo() != null;
        }).collect(Collectors.toList());

        for (CommodityClassificationAllLevelListDTO levelListDTO : allLevelListDTOS) {
            for (CommodityClassificationLevelTwoDTO levelTwoDTO : levelListDTO.getLevelTwo()) {
                levelTwoDTO.setPictureUrl(levelTwoDTO.getIcon());
            }
        }
        log.info("【中旅商城--C端--级联分类获取--end】");
        return Result.success(allLevelListDTOS);
    }

    /**
     * 更新商城首页缓存
     */
    @Override
    public Result updateGoodsCache(CommodityPageReq pageReq, TokenUser tokenUser) {

        try {
            List<CommodityInfoListDTO> commodityAllList = findCommodityAllList(null);

            List<CommodityInfoListDTO> commodityAllList2 = new ArrayList<>();

            // 查询商品七天内的销售数据
            List<com.ctshk.rpc.goods.dto.resp.CountVo> salesMap = commodityService.findSavenDaysCommodityNumber();
            if (org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty(commodityAllList)) {
                log.info("【查询商品数据封装，数据返参为:{}】", JSON.toJSONString(commodityAllList));
                for (CommodityInfoListDTO commodityInfoListDTO : commodityAllList) {
                    if (org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty(salesMap)) {
                        log.info("【查询商品七天内的销售数据，数据返参为:{}】", JSON.toJSONString(salesMap));
                        for (com.ctshk.rpc.goods.dto.resp.CountVo stringStringMap : salesMap) {
                            if (commodityInfoListDTO.getId().longValue() == Long.parseLong(stringStringMap.getCommodityId())) {
                                commodityInfoListDTO.setSales(Long.parseLong(stringStringMap.getCount()));
                            } else {
                                commodityInfoListDTO.setSales(0L);
                            }
                        }
                    } else {
                        commodityInfoListDTO.setSales(0L);
                    }
                    commodityAllList2.add(commodityInfoListDTO);
                }
                //        List<CommodityAllListDTO> commodityAllList1 = commodityMapper.findCommodityAllList(null);
                upClassificationEs(commodityAllList2);
            }

            // 查询父子级分类名称集合列表
            List<CommodityClassificationAllLevelListDTO> classificationByAllLevel = classificationService.findClassificationByAllLevel(null);
            if (org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty(classificationByAllLevel)) {
                log.info("【查询父子级分类名称集合列表，数据返参为:{}】", JSON.toJSONString(classificationByAllLevel));
                Collections.sort(classificationByAllLevel, new Comparator<CommodityClassificationAllLevelListDTO>() {
                    @Override
                    public int compare(CommodityClassificationAllLevelListDTO o1, CommodityClassificationAllLevelListDTO o2) {
                        if (null != o1.getSort() && null != o2.getSort()) {
                            if (o1.getSort() > o2.getSort()) {
                                return 1;
                            }
                            if (o1.getSort() == o2.getSort()) {
                                return 0;
                            }
                        }
                        return -1;
                    }
                });
                List<CommodityClassificationLevelTwoDTO> dbLevelTwoData = new ArrayList<>();
                for (CommodityClassificationAllLevelListDTO levelListDTO : classificationByAllLevel) {
                    if (org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty(levelListDTO.getLevelTwo())) {
                        for (CommodityClassificationLevelTwoDTO levelTwoDTO : levelListDTO.getLevelTwo()) {
                            CommodityClassificationLevelTwoDTO levelTwo = EntityUtil.copy(levelTwoDTO, CommodityClassificationLevelTwoDTO.class);
                            // 0、不显示首页 1、显示首页
                            if (null != levelTwo && levelTwo.getIsDisplay().intValue() == 1) {
                                if(null != levelTwo.getStatus() && levelTwo.getStatus().intValue() == 1){
                                    dbLevelTwoData.add(levelTwo);
                                }
                            }
                        }
                    }
                }
                // 上架redis
                String jsonString = JSON.toJSONString(dbLevelTwoData);
                redisTemplate.delete(RedisConstants.GOODS_HOME_CLASSIFICATION);
                redisTemplate.opsForValue().set(RedisConstants.GOODS_HOME_CLASSIFICATION, jsonString);

                String classificationByAllLevels = JSON.toJSONString(classificationByAllLevel);
                redisTemplate.delete(RedisConstants.GOODS_HOME_CLASSIFICATION_ALL);
                redisTemplate.opsForValue().set(RedisConstants.GOODS_HOME_CLASSIFICATION_ALL, classificationByAllLevels);
            } else {
                log.error("【查询父子级分类名称集合列表错误，数据为空】");
            }

            // 查询商品专题列表
//        QueryWrapper<ShoppingSpecial> specialQueryWrapper = new QueryWrapper<>();
            List<ShoppingSpecial> shoppingSpecials = shoppingSpecialMapper.selectAllList();
            List<ShoppingSpecialDetailedDTO> specialPageDTOS = new ArrayList<>();
            List<Long> ids = new ArrayList<>();
            if (!CollectionUtils.isEmpty(shoppingSpecials)) {
                log.info("【查询商品专题列表，数据返参为:{}】", JSON.toJSONString(shoppingSpecials));
                // 获取专题信息
                for (ShoppingSpecial special : shoppingSpecials) {
                    ShoppingSpecialDetailedDTO specialDetailedDTO = EntityUtil.copy(special, ShoppingSpecialDetailedDTO.class);
                    List<ShoppingSpecialCommodityDetailedDTO> shoppingSpecialCommodityDetailedDTOS = new ArrayList<>();
                    // 查询专题商品信息
                    //                QueryWrapper<ShoppingSpecialCommodity> shoppingSpecialCommodityQueryWrapper = new QueryWrapper<>();
                    //                shoppingSpecialCommodityQueryWrapper.eq("special_id", special.getId());
                    List<ShoppingSpecialCommodity> shoppingSpecialCommodities = shoppingSpecialCommodityMapper.selectAllList(special.getId());
                    if (!CollectionUtils.isEmpty(shoppingSpecialCommodities)) {
                        // 获取商品详细信息
                        for (ShoppingSpecialCommodity specialCommodity : shoppingSpecialCommodities) {
                            ids.add(specialCommodity.getCommodityId());
                        }
                        List<CommodityInfoResp> commodityInfoResps = new ArrayList<>();
                        // 构建DSL语句
                        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
                        QueryBuilder queryBuilder = QueryBuilders.termsQuery("id", ids);
                        sourceBuilder.query(queryBuilder);
                        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.GOODS_INDEX).source(sourceBuilder);
                        try {
                            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
                            commodityInfoResps = buildCommodityInfoResp(searchResponse);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        for (CommodityInfoResp commodityInfoResp : commodityInfoResps) {
                            ShoppingSpecialCommodityDetailedDTO specialCommodityDetailedDTO = EntityUtil.copy(commodityInfoResp, ShoppingSpecialCommodityDetailedDTO.class);
                            if (org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty(commodityInfoResp.getCommodityCost())) {
                                specialCommodityDetailedDTO.setPrice(commodityInfoResp.getCommodityCost().get(0).getCostPrice());
                                specialCommodityDetailedDTO.setMarkingPrice(commodityInfoResp.getCommodityCost().get(0).getMarkingPrice());
                            }
                            specialCommodityDetailedDTO.setLabelType(commodityInfoResp.getLabelType());
                            shoppingSpecialCommodityDetailedDTOS.add(specialCommodityDetailedDTO);
                        }
                        specialDetailedDTO.setCommodityDetailedList(shoppingSpecialCommodityDetailedDTOS);
                    }
                    specialPageDTOS.add(specialDetailedDTO);
                }
                redisTemplate.delete(RedisConstants.GOODS_HOME_SPECIAL);
                // 上架Redis
                redisTemplate.opsForValue().set(RedisConstants.GOODS_HOME_SPECIAL, JSON.toJSONString(specialPageDTOS));
            } else {
                for (ShoppingSpecial special : shoppingSpecials) {
                    ShoppingSpecialPageDTO pageDTO = EntityUtil.copy(special, ShoppingSpecialPageDTO.class);
                    //                specialPageDTOS.add(pageDTO);
                }
                redisTemplate.delete(RedisConstants.GOODS_HOME_SPECIAL);
                // 上架Redis
                redisTemplate.opsForValue().set(RedisConstants.GOODS_HOME_SPECIAL, JSON.toJSONString(specialPageDTOS));
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
            throw new BusinessException(SystemError.SYS_502);
        }
        return Result.success();
    }

    /**
     * 获取到所有的商品成本后，根据商品属性分组
     *
     * @param singles 单规格商品集合
     * @return 商品属性分组后的商品集合
     */
    private Map<Long, List<CommodityCostDTO>> getSingleCommodityCostMapByAttributeId(List<CommodityInfoListDTO> singles) {
        Map<Long, List<CommodityCostDTO>> result = null;
        List<Long> singleCommodityIds = singles.stream().map(p -> p.getId()).collect(Collectors.toList());
        List<CommodityCost> list = costMapper.selectListByIds(singleCommodityIds, IsDeletedCode.NO.getCode());
        List<CommodityCostDTO> resultList = EntityUtil.copyList(
                list, CommodityCostDTO.class);
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(resultList)) {
            result = resultList.stream().collect(Collectors.groupingBy(obj -> obj.getCommodityAttributeId()));
        }
        return result;
    }

    /**
     * 获取到所有的商品成本属性后，根据属性分组
     *
     * @param multiples 多规格商品集合
     * @return 商品属性集合
     */
    private Map<Long, List<CommodityCostAttributeDTO>> getMultipleCommodityCostAttributeMapByAttributeId(List<CommodityInfoListDTO> multiples) {
        Map<Long, List<CommodityCostAttributeDTO>> result = null;
        List<Long> multipleCommodityIds = multiples.stream().map(p -> p.getId()).collect(Collectors.toList());
        List<CommodityCostAttribute> list = costAttributeMapper.selectByIds(multipleCommodityIds, IsDeletedCode.NO.getCode());
        List<CommodityCostAttributeDTO> costAttributeList = EntityUtil.copyList(list, CommodityCostAttributeDTO.class);
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(costAttributeList)) {
            result = costAttributeList.stream().collect(Collectors.groupingBy(obj -> obj.getCommodityAttributeId()));
        }
        return result;
    }

    /**
     * 查询商品数据封装
     *
     * @param lastNow
     * @return
     */
    public List<CommodityInfoListDTO> findCommodityAllList(LocalDateTime lastNow) {
        // 过滤商品主表数据，根据主表数据去组装其他数据参数
        List<CommodityInfoListDTO> commodityList = commodityMapper.findCommodityInfoList(lastNow);
        if (CollectionUtils.isEmpty(commodityList)) {
            return null;
        }
        Map<Long, List<CommodityLabelDTO>> labelMap = null;
        Map<Long, List<CommodityFileDTO>> fileMap = null;
        Map<Long, List<CommodityKeyWordDTO>> keyWordMap = null;
        Map<Long, List<CommodityRecommendDTO>> recommendMap = null;
        Map<Long, List<CommodityInfoListDTO>> singlesMap = null;

        List<Long> commodityIds = commodityList.stream().map(p -> p.getId()).collect(Collectors.toList());

        // 获取商品标签，并根据商品ID进行分组，用于后续的组装参数取值
        List<CommodityLabelDTO> labelList = labelMapper.findHtmlFiveCommodityLabelByCommodityIds(commodityIds);
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(labelList)) {
            labelMap = labelList.stream().collect(Collectors.groupingBy(obj -> obj.getCommodityId()));
        }

        // 获取商品文件，并根据商品ID进行分组，用于后续的组装参数取值
        List<CommodityFileDTO> fileList = fileMapper.findHtmlFiveCommodityFileByCommodityIds(commodityIds);
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(fileList)) {
            fileMap = fileList.stream().collect(Collectors.groupingBy(obj -> obj.getCommodityId()));
        }

        // 获取商品关键词，并根据商品ID进行分组，用于后续的组装参数取值
        List<CommodityKeyWordDTO> keyWordList = keyWordMapper.findHtmlFiveCommodityKeyWordByCommodityIds(commodityIds);
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(keyWordList)) {
            keyWordMap = keyWordList.stream().collect(Collectors.groupingBy(obj -> obj.getCommodityId()));
        }

        // 获取商品推荐，并根据商品ID进行分组，用于后续的组装参数取值
        List<CommodityRecommendDTO> recommendList = recommendMapper.findHtmlFiveCommodityRecommendByCommodityIds(commodityIds);
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(recommendList)) {
            recommendMap = recommendList.stream().collect(Collectors.groupingBy(obj -> obj.getCommodityId()));
        }

        // 商品其他属性 一对一 查询赋值
        for (CommodityInfoListDTO commodityAllList : commodityList) {
            Long commodityId = commodityAllList.getId();
            commodityAllList.setId(commodityId);
            commodityAllList.setCommodityLabels(null == labelMap ? null : labelMap.get(commodityId));
            commodityAllList.setCommodityFiles(null == fileMap ? null : fileMap.get(commodityId));
            commodityAllList.setCommodityKeyWords(null == keyWordMap ? null : keyWordMap.get(commodityId));
            commodityAllList.setCommodityRecommends(null == recommendMap ? null : recommendMap.get(commodityId));
        }

        // 区分 单/多规格类型数据，因为组装的参数涉及表关联关系不一样
        Map<Integer, List<CommodityInfoListDTO>> specificationsTypeMap = commodityList.stream().collect(Collectors.groupingBy(obj -> obj.getCommodityAttribute().getSpecificationsType()));
        List<CommodityInfoListDTO> singles = specificationsTypeMap.get(1);
        List<CommodityInfoListDTO> multiples = specificationsTypeMap.get(2);

        // 单规格参数组装
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(singles)) {
            Map<Long, List<CommodityCostDTO>> costs = getSingleCommodityCostMapByAttributeId(singles);
            for (CommodityInfoListDTO singlesCommodityAllList : singles) {
                Long commodityAttributeId = singlesCommodityAllList.getCommodityAttribute().getId();
                List<CommodityCostDTO> temps = costs.get(commodityAttributeId);
                if (org.apache.commons.collections.CollectionUtils.isNotEmpty(temps)) {
                    singlesCommodityAllList.setCommodityCosts(temps);
                }
            }
//            singlesMap = singles.stream().collect(Collectors.groupingBy(obj -> obj.getId()));
            for (CommodityInfoListDTO commodityAllList : commodityList) {
                for (CommodityInfoListDTO single : singles) {
                    if (commodityAllList.getId().longValue() == single.getId().longValue()) {
                        commodityAllList.setCommodityCosts(null == single ? null : single.getCommodityCosts());
                    }
                }
            }
        }

        // 多规格参数组装
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(multiples)) {
            Map<Long, List<CommodityCostAttributeDTO>> costAttributes = getMultipleCommodityCostAttributeMapByAttributeId(multiples);
            for (CommodityInfoListDTO multipleCommodityAllList : multiples) {
                Long commodityAttributeId = multipleCommodityAllList.getCommodityAttribute().getId();
                List<CommodityCostAttributeDTO> temps = costAttributes.get(commodityAttributeId);
                if (org.apache.commons.collections.CollectionUtils.isNotEmpty(temps)) {
                    multipleCommodityAllList.setCommodityCostAttributes(temps); // 讲商品成本属性设置到对应的商品对象
                    // 获取商品成本属相对应的商品成本
                    List<Long> costAttributeIds = temps.stream().map(p -> p.getId()).collect(Collectors.toList());
                    List<CommodityCost> commodityCostList = costMapper.selectByCommodityIdAndAttrId(multipleCommodityAllList.getCommodityAttribute().getCommodityId(), commodityAttributeId, costAttributeIds, IsDeletedCode.NO.getCode());
                    List<CommodityCostDTO> resultCostList = EntityUtil.copyList(commodityCostList, CommodityCostDTO.class);
                    Map<Long, List<CommodityCostDTO>> costAttributeMap = resultCostList.stream().collect(Collectors.groupingBy(obj -> obj.getCostAttributeId()));

                    for (CommodityCostAttributeDTO costAttribute : multipleCommodityAllList.getCommodityCostAttributes()) {
                        Long costAttributeId = costAttribute.getId();
                        List<CommodityCostDTO> commodityCost = costAttributeMap.get(costAttributeId);
                        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(commodityCost)) {
                            costAttribute.setCommodityCost(commodityCost.get(0));
                        }
                    }
                }
            }
//            for (CommodityInfoListDTO commodityAllList : commodityList) {
//                for (CommodityInfoListDTO multiple : multiples) {
//                    if (commodityAllList.getId().longValue() == multiple.getId().longValue()) {
//                        commodityAllList.setCommodityCosts(null == multiple ? null : multiple.getCommodityCosts());
//                    }
//                }
//            }
        }
        return commodityList;
    }

    /**
     * 构建PC 检索结果
     *
     * @param response
     * @return
     */
    public List<CommodityInfoResp> buildCommodityInfoResp(SearchResponse response) {
        List<CommodityInfoResp> commodityInfoResps = new ArrayList<>();

        // 检索到的命中记录
        SearchHits hits = response.getHits();

        // 提取检索到的记录
        SearchHit[] searchHits = hits.getHits();
        if (searchHits != null && searchHits.length > 0) {
            for (SearchHit hit : searchHits) {
                CommodityInfoResp commodityInfoResp = new CommodityInfoResp();
                String source = hit.getSourceAsString();
                // 将命中记录反序列化成行程对象和目的地对象
                CommodityInfoListDTO commodityInfoListDTO = JSON.parseObject(source, CommodityInfoListDTO.class);
                log.info("【命中结果为：{}】", JSON.toJSONString(commodityInfoListDTO));
                commodityInfoResp.setCommodityName(commodityInfoListDTO.getCommodityName());
                // 单规格
                List<CommodityCostResp> commodityCosts = new ArrayList<>();
                if (org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty(commodityInfoListDTO.getCommodityCosts())) {
                    for (CommodityCostDTO commodityCost : commodityInfoListDTO.getCommodityCosts()) {
                        CommodityCostResp cost = new CommodityCostResp();
                        cost.setCostPrice(commodityCost.getCostPrice());
                        cost.setMarkingPrice(commodityCost.getMarkingPrice());
                        cost.setPictureUrl(commodityCost.getPictureUrl());
                        commodityCosts.add(cost);
                    }
                }
                // 多规格
                List<CommodityCostAttributeResp> commodityCostAttributeResps = new ArrayList<>();
                if (org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty(commodityInfoListDTO.getCommodityCostAttributes())) {
                    for (CommodityCostAttributeDTO commodityCostAttribute : commodityInfoListDTO.getCommodityCostAttributes()) {
                        CommodityCostResp cost = new CommodityCostResp();
                        cost.setCostPrice(commodityCostAttribute.getCommodityCost().getCostPrice());
                        cost.setMarkingPrice(commodityCostAttribute.getCommodityCost().getMarkingPrice());
                        cost.setPictureUrl(commodityCostAttribute.getCommodityCost().getPictureUrl());
                        commodityCosts.add(cost);
//                        CommodityCostAttributeResp commodityCostAttributeResp = new CommodityCostAttributeResp();
//                        commodityCostAttributeResp.setCostPrice(commodityCostAttribute.getCommodityCost().getCostPrice());
//                        commodityCostAttributeResp.setMarkingPrice(commodityCostAttribute.getCommodityCost().getMarkingPrice());
//                        commodityCostAttributeResp.setPictureUrl(commodityCostAttribute.getCommodityCost().getPictureUrl());
//                        commodityCostAttributeResps.add(commodityCostAttributeResp);
                    }
                }
                // 商品属性
                if (null != commodityInfoListDTO.getCommodityAttribute()) {
                    commodityInfoResp.setCommodityAttribute(commodityInfoListDTO.getCommodityAttribute());
                }
                // 商品标签
                if (org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty(commodityInfoListDTO.getCommodityLabels())) {
                    for (CommodityLabelDTO commodityLabel : commodityInfoListDTO.getCommodityLabels()) {
                        commodityInfoResp.setLabelType(commodityLabel.getLabelType());
                    }
                }
                List<CommodityFileDTO> commodityFileList = new ArrayList<>();
                if (org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty(commodityInfoListDTO.getCommodityFiles())) {
                    for (CommodityFileDTO commodityFile : commodityInfoListDTO.getCommodityFiles()) {
                        if (commodityFile.getFileType().intValue() == 2) {
                            CommodityFileDTO commodityFileDTO = new CommodityFileDTO();
                            Long commodityId = commodityFile.getCommodityId();
                            Long id = commodityFile.getId();
                            String fileName = commodityFile.getFileName();
                            String fileUrl = commodityFile.getFileUrl();
                            Integer fileType = commodityFile.getFileType();
                            Integer isDeleted = commodityFile.getIsDeleted();
                            commodityFileDTO.setCommodityId(commodityId);
                            commodityFileDTO.setFileName(fileName);
                            commodityFileDTO.setFileType(fileType);
                            commodityFileDTO.setFileUrl(fileUrl);
                            commodityFileDTO.setIsDeleted(isDeleted);
                            commodityFileDTO.setId(id);
                            commodityFileList.add(commodityFileDTO);
                        }
                    }
                    commodityInfoResp.setCommodityFileList(commodityFileList);
                }
                Long sales = commodityInfoListDTO.getSales();
                if (null != sales) {
                    commodityInfoResp.setSales(sales.toString());
                }
                commodityInfoResp.setId(commodityInfoListDTO.getId());
                commodityInfoResp.setCommodityClassificationId(commodityInfoListDTO.getCommodityClassificationId());
                String commodityClassificationName = commodityInfoListDTO.getCommodityClassificationName();
                commodityInfoResp.setCommodityClassificationName(commodityClassificationName);
                commodityInfoResp.setCommodityCostAttributes(commodityCostAttributeResps);
                commodityInfoResp.setCommodityCost(commodityCosts);
                commodityInfoResp.setCommodityName(commodityInfoListDTO.getCommodityName());
                commodityInfoResps.add(commodityInfoResp);
            }
        }
        return commodityInfoResps;
    }

    @Override
    public Result<PageResponse<CommodityInfoResp>> getTwoLevel(String towLevelId, Integer statusCode, Integer page, Integer size) {
        if (null == page || null == size) {
            page = 1;
            size = 10;
        }
        if (StringUtils.isEmpty(towLevelId) || null == statusCode) {
            return Result.failed(SystemError.SYS_402);
        }
        // 构建DSL语句
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        if (!hasKey(RedisConstants.GOODS_HOME_CLASSIFICATION)) {
            return Result.success(null);
        }
        // 查询二级分类的id
        String str = (String) redisTemplate.opsForValue().get(RedisConstants.GOODS_HOME_CLASSIFICATION);
        List<CommodityClassificationAllLevelListDTO> allLevelListDTOS = JSON.parseObject(str, new TypeReference<List<CommodityClassificationAllLevelListDTO>>() {
        });
        allLevelListDTOS = allLevelListDTOS.stream().filter(level -> {
            return level.getLevelTwo() != null;
        }).collect(Collectors.toList());
        List<Long> ids = new ArrayList<>();
        for (CommodityClassificationAllLevelListDTO levelListDTO : allLevelListDTOS) {
            List<com.ctshk.rpc.order.goods.dto.CommodityClassificationLevelTwoDTO> levelTwo = levelListDTO.getLevelTwo();
            for (CommodityClassificationLevelTwoDTO twoDTO : levelTwo) {
                ids.add(twoDTO.getId());
            }
        }
        // 1、构建bool - query
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // filter - 过滤 - 按照2级分类Id检索
//        if (ids != null && ids.size() > 0) {
        boolQuery.filter(QueryBuilders.termQuery("commodityClassificationId", towLevelId));
//        }

        if (null == statusCode) {
            statusCode = 1;
        }
        // 默认排序,七天内销量
        if (statusCode == 1) {
            sourceBuilder.sort(new FieldSortBuilder("sales").order(SortOrder.DESC));
        }
        // 新品排序
        else if (statusCode == 2) {
            sourceBuilder.sort(new FieldSortBuilder("gmtModified").order(SortOrder.DESC));
        }
        // 价格排序
        else if (statusCode == 3) {
            sourceBuilder.sort(new FieldSortBuilder("commodityCosts.price").order(SortOrder.DESC));
        }
        // 价格排序(降序)
        else if (statusCode == 4) {
            sourceBuilder.sort(new FieldSortBuilder("commodityCosts.price").order(SortOrder.ASC));
        }// 新品排序（降序）
        else if (statusCode == 5) {
            sourceBuilder.sort(new FieldSortBuilder("gmtModified").order(SortOrder.ASC));
        }

        List<CommodityInfoResp> commodityInfoResps = new ArrayList<>();
//        sourceBuilder.query((new BoolQueryBuilder()).must(QueryBuilders.termsQuery("commodityClassificationId", ids)));
        // 查询结果需要返回的字段和不需要返回的字段
//        sourceBuilder.fetchSource(new String[]{"classificationName", "id", "commodityCost.price", "commodityCost.markingPrice", "classificationNumber", "classificationName", "classificationSort", "commodityName", "commodityClassificationId"}, new String[]{});
        sourceBuilder.query(boolQuery).size(8);
        /*聚合分类*/
        NestedAggregationBuilder goodsTerm_agg = AggregationBuilders.nested(ElasticSearchConstant.GOODS_AGG, ElasticSearchConstant.GOODS_PATH);
        TermsAggregationBuilder goods_price_agg = AggregationBuilders.terms(ElasticSearchConstant.GOODS_PRICE_AGG).field(ElasticSearchConstant.GOODS_PRICE);
        goods_price_agg.subAggregation(AggregationBuilders.terms(ElasticSearchConstant.GOODS_MARKINGPRICE_AGG).field(ElasticSearchConstant.GOODS_MARKINGPRICE));
        goodsTerm_agg.subAggregation(goods_price_agg);
        sourceBuilder.aggregation(goodsTerm_agg);
        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.GOODS_INDEX).source(sourceBuilder);
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            commodityInfoResps = buildCommodityInfoResp(searchResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }
        PageResponse<CommodityInfoResp> response = new PageResponse<CommodityInfoResp>(commodityInfoResps, page == 1, commodityInfoResps.size() <= (page * size), commodityInfoResps.size(), page, size);
        return Result.success(response);
    }

    @Autowired
    private CommoditySpecificationsAttributeMapper commoditySpecificationsAttributeMapper;

    @Override
    public Result<CommodityInfo> info(String id, Long userId) {
        log.info("【中旅商城--商品详情--start】,入参为:{}", id);
        if (null == id) {
            return Result.failed(SystemError.SYS_402);
        }

        LocalDateTime now = LocalDateTime.now();

//        if (hasKey(RedisConstants.GOODS_COMMODITY_INFO)) {
        // 后台更新商品信息做缓存
//            if (hasKey(RedisConstants.GOODS_COMMODITY_TIME_CART)){
//                LocalDateTime dateTime = JSON.parseObject(redisTemplate.opsForValue().get(RedisConstants.GOODS_COMMODITY_TIME_CART), LocalDateTime.class);
//                if (now.isBefore(dateTime)){
//                    redisTemplate.opsForValue().set(RedisConstants.GOODS_COMMODITY_TIME_CART,JSON.toJSONString(now));
//                }else{
//
//                }
//            }
        // 查询redis的商品信息
//            String str = redisTemplate.opsForValue().get(RedisConstants.GOODS_COMMODITY_INFO);
//            return Result.success(JSONArray.parseObject(str, CommodityInfo.class));
//        }

        // 查询商品信息
//        QueryWrapper<Commodity> commodityQueryWrapper = new QueryWrapper<>();
//        commodityQueryWrapper.eq("id", id);
        Commodity commodity = commodityMapper.selectCommodityById(id);
        log.info("【中旅商城--商品详情--查询商品信息】,返参为:{}", JSON.toJSONString(commodity));
        if (commodity == null) {
            return Result.failed(SystemError.GOODS_ORDER_ERROR_40001);
        }
        CommodityInfo commodityInfo = new CommodityInfo();
        commodityInfo.setFreightTemplateId(commodity.getFreightTemplateId()); // 运费模板id
        commodityInfo.setCommodityDetails(commodity.getCommodityDetails()); // 商品详情
        commodityInfo.setIsItSelfProvided(commodity.getIsItSelfProvided()); //是否允许自提
        commodityInfo.setId(commodity.getId()); // 商品id
        commodityInfo.setCommodityName(commodity.getCommodityName()); // 商品名称
        commodityInfo.setCommodityNumber(commodity.getCommodityNumber()); // 商品编码

        List<JSONObject> specificationList = new ArrayList<>();

        // 查询商品分类
        if (null != commodity.getCommoditySpecificationsNameId()) {
            List<CommoditySpecifications> commoditySpecifications = costAttributeMapper.findBatchSpecificationsByNameId(commodity.getCommoditySpecificationsNameId());
            if (org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty(commoditySpecifications)) {
                for (CommoditySpecifications specifications : commoditySpecifications) {
                    if (specifications.getSpecifications() != null && specifications.getId() != null) {
                        JSONObject oneObject = new JSONObject();
                        oneObject.put("id", specifications.getId());
                        oneObject.put("specifications", specifications.getSpecifications());
                        List<CommoditySpecificationsAttribute> commoditySpecificationsAttributes = commoditySpecificationsAttributeMapper.findBySpecificationsId(specifications.getId());
//                        for (CommoditySpecificationsAttribute attribute : commoditySpecificationsAttributes) {
//                            Long specificationsId = attribute.getSpecificationsId();
//                            String attributeName = attribute.getAttributeName();
//                        }
                        oneObject.put("specificationAttrs", commoditySpecificationsAttributes);
                        specificationList.add(oneObject);
                    }
                }
            }
        }
        commodityInfo.setCommoditySpecificationsList(specificationList);

        // 查询商品分类
//        QueryWrapper<CommodityClassification> commodityClassificationQueryWrapper = new QueryWrapper<>();
//        commodityClassificationQueryWrapper.eq("id", commodity.getCommodityClassificationId());
        CommodityClassification commodityClassification = commodityClassificationMapper.selectClassficationById(commodity.getCommodityClassificationId());
        log.info("【中旅商城--商品详情--查询商品分类】,返参为:{}", JSON.toJSONString(commodityClassification));
        if (commodityClassification == null) {
//            return Result.failed(SystemError.GOODS_ORDER_ERROR_40002);
            commodityInfo.setClassificationName(null);
        } else {
            commodityInfo.setClassificationName(commodity.getCommodityClassificationName()); // 分类名称
        }

        // 查询商品属性
//        QueryWrapper<CommodityAttribute> commodityAttributeQueryWrapper = new QueryWrapper<>();
//        commodityAttributeQueryWrapper.eq("commodity_id", commodity.getId());
        CommodityAttribute commodityAttribute = commodityAttributeMapper.selectAttributeByCommodityId(commodity.getId());
        log.info("【中旅商城--商品详情--查询商品属性】,返参为:{}", JSON.toJSONString(commodityAttribute));
        if (commodityAttribute == null) {
//            return Result.failed(SystemError.GOODS_ORDER_ERROR_40003);
            commodityInfo.setCurrencyId(null); // 币种id
            commodityInfo.setCurrencyName(null); // 币种名称
            commodityInfo.setExchangeRate(null); // 悦换率
            commodityInfo.setSpecificationsType(null); // 规格
        } else {
            commodityInfo.setCurrencyId(commodityAttribute.getCurrencyId()); // 币种id
            commodityInfo.setCurrencyName(commodityAttribute.getCurrencyName()); // 币种名称
            commodityInfo.setExchangeRate(commodityAttribute.getExchangeRate()); // 悦换率
            commodityInfo.setSpecificationsType(commodityAttribute.getSpecificationsType()); // 规格
        }

        // 查询商品成本属性
//        QueryWrapper<CommodityCostAttribute> commodityCostAttributeQueryWrapper = new QueryWrapper<>();
//        commodityCostAttributeQueryWrapper.eq("commodity_attribute_id", commodityAttribute.getId());// 商品属性id
//        commodityCostAttributeQueryWrapper.eq("commodity_id", commodity.getId()); // 商品id
        // 单规格
        if (commodityAttribute.getSpecificationsType().intValue() == 1) {
            CommodityCost commodityCost = commodityCostMapper.findCommodityCostByCommodityId(commodity.getId());
            if (null == commodityCost) {
                commodityInfo.setCommodityCostListResp(null);
            } else {
                // 查询规格下的价格最低
                List<CommodityCostListResp> costListResp = new ArrayList<>();
                CommodityCostListResp costListResp1 = new CommodityCostListResp();
                costListResp1.setCostAttributeId(commodityCost.getCostAttributeId());
                costListResp1.setCostPrice(commodityCost.getCostPrice());
                costListResp1.setStock(commodityCost.getStock());
                costListResp1.setWeight(commodityCost.getWeight());
                costListResp1.setMarkingPrice(commodityCost.getMarkingPrice());
                costListResp1.setPictureUrl(commodityCost.getPictureUrl());
                costListResp1.setId(commodityCost.getId());
                costListResp.add(costListResp1);
                commodityInfo.setCommodityCostListResp(costListResp);
            }
        } else if (commodityAttribute.getSpecificationsType().intValue() == 2) { // 多规格
            List<CommodityCostAttribute> commodityCostAttributes = commodityCostAttributeMapper.selectAllList(commodityAttribute.getId(), commodity.getId());
            log.info("【中旅商城--商品详情--查询商品成本属性】,返参为:{}", JSON.toJSONString(commodityCostAttributes));
            List<CommodityCostAttributeListResp> costAttributeList = new ArrayList<>();
            if (commodityCostAttributes == null || CollectionUtils.isEmpty(commodityCostAttributes)) {
//            return Result.failed(SystemError.GOODS_ORDER_ERROR_40005);
                commodityInfo.setCommodityCostAttributeList(costAttributeList);
            } else {
                // 保存属性信息用以后面的查询结果过滤，不然会显示所有的规格属性的
                List<JSONObject> commodityCostAttributeLists = new ArrayList<>();
                for (CommodityCostAttribute costAttribute : commodityCostAttributes) {
                    CommodityCostAttributeListResp costAttributeListResp = new CommodityCostAttributeListResp();
                    costAttributeListResp.setId(costAttribute.getId());
                    costAttributeListResp.setSpecificationsAttributeOneId(costAttribute.getSpecificationsAttributeOneId()); // 属性1 id
                    costAttributeListResp.setSpecificationsAttributeOneName(costAttribute.getSpecificationsAttributeOneName()); // 属性1 名称
                    costAttributeListResp.setSpecificationsAttributeTwoId(costAttribute.getSpecificationsAttributeTwoId()); // 属性2 id
                    costAttributeListResp.setSpecificationsAttributeTwoName(costAttribute.getSpecificationsAttributeTwoName()); // 属性2 名称
                    costAttributeList.add(costAttributeListResp);
                }
                commodityInfo.setCommodityCostAttributeList(costAttributeList);
            }

            // 查询商品成本
//        QueryWrapper<CommodityCost> commodityCostQueryWrapper = new QueryWrapper<>();
//        commodityCostQueryWrapper.eq("commodity_attribute_id", commodityAttribute.getId());
//        commodityCostQueryWrapper.eq("commodity_id", commodity.getId());
            List<Long> ids = new ArrayList<>();
            for (CommodityCostAttribute costAttribute : commodityCostAttributes) {
                ids.add(costAttribute.getId());
            }
//        commodityCostQueryWrapper.in("cost_attribute_id", ids);
            List<CommodityCost> commodityCosts = commodityCostMapper.selectAllList(commodityAttribute.getId(), commodity.getId(), ids);
            log.info("【中旅商城--商品详情--查询商品成本】,返参为:{}", JSON.toJSONString(commodityCosts));
            if (commodityCosts == null || CollectionUtils.isEmpty(commodityCosts)) {
//            return Result.failed(SystemError.GOODS_ORDER_ERROR_40004);
                commodityInfo.setCommodityCostListResp(null);
            } else {

                // 查询规格下的价格最低
                Collections.sort(commodityCosts, new Comparator<CommodityCost>() {
                    @Override
                    public int compare(CommodityCost o1, CommodityCost o2) {
                        if (o1.getCostPrice().compareTo(o2.getCostPrice()) == 1) {
                            return 1;
                        }
                        if (o1.getCostPrice().compareTo(o2.getCostPrice()) == 0) {
                            return 0;
                        }
                        return -1;
                    }
                });
                List<CommodityCostListResp> costListResp = new ArrayList<>();
                for (CommodityCost commodityCost1 : commodityCosts) {

                    CommodityCostListResp costListResp1 = new CommodityCostListResp();
                    costListResp1.setCostAttributeId(commodityCost1.getCostAttributeId());
                    costListResp1.setCostPrice(commodityCost1.getCostPrice());
                    costListResp1.setStock(commodityCost1.getStock());
                    costListResp1.setWeight(commodityCost1.getWeight());
                    costListResp1.setMarkingPrice(commodityCost1.getMarkingPrice());
                    costListResp1.setPictureUrl(commodityCost1.getPictureUrl());
                    costListResp1.setId(commodityCost1.getId());
                    costListResp.add(costListResp1);
                }
                commodityInfo.setCommodityCostListResp(costListResp);
            }
        }
        // 查询商品区域
//        QueryWrapper<CommoditySalesArea> commoditySalesAreaQueryWrapper = new QueryWrapper<>();
//        commoditySalesAreaQueryWrapper.eq("commodity_attribute_id", commodityAttribute.getId());
//        commoditySalesAreaQueryWrapper.eq("commodity_id", commodity.getId());
        List<CommoditySalesArea> commoditySalesAreas = commoditySalesAreaMapper.selectSaleById(commodityAttribute.getId(), commodity.getId());

        log.info("【中旅商城--商品详情--查询商品区域】,返参为:{}", JSON.toJSONString(commoditySalesAreas));
        if (CollectionUtils.isEmpty(commoditySalesAreas)) {
//            return Result.failed(SystemError.GOODS_ORDER_ERROR_40006);
            commodityInfo.setAreaType(null);
        } else {
            List<Integer> areas = new ArrayList<>();
            for (CommoditySalesArea commoditySalesArea : commoditySalesAreas) {
                areas.add(commoditySalesArea.getAreaType());
            }
            commodityInfo.setAreaType(areas);
        }

        // 查询商品文件
        List<CommodityFile> fileByCommodityId = commodityFileMapper.findCommodityFileByCommodityId(commodity.getId());
        log.info("【中旅商城--商品详情--查询商品文件】,返参为:{}", JSON.toJSONString(fileByCommodityId));
        if (org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty(fileByCommodityId)) {
//            for (CommodityFile commodityFile : fileByCommodityId) {
//                if (commodityFile.getFileType().intValue() == 2){
            List<CommodityFileDTO> commodityFileDTO = EntityUtil.copyList(fileByCommodityId, CommodityFileDTO.class);
            commodityInfo.setCommodityFileDTO(commodityFileDTO);
//                }
//            }
        }

        // 查询商品标签类型
//        QueryWrapper<CommodityLabel> commodityLabelQueryWrapper = new QueryWrapper<>();
//        commodityLabelQueryWrapper.eq("commodity_id", commodity.getId());
        List<CommodityLabel> commodityLabel = commodityLabelMapper.selecAlltList(commodity.getId());
        if (org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty(commodityLabel)) {
            log.info("【中旅商城--商品详情--查询商品标签类型】,返参为:{}", JSON.toJSONString(commodityLabel));
            commodityInfo.setLabelType(commodityLabel.get(0).getLabelType());
        }

        // 设置图片
        if (null != commodityInfo.getCommodityCostListResp().get(0).getPictureUrl()) {
            List<ShoppingSpecialPageUrlDTO> list = JSON.parseArray(commodityInfo.getCommodityCostListResp().get(0).getPictureUrl(), ShoppingSpecialPageUrlDTO.class);
            commodityInfo.getCommodityCostListResp().get(0).setPictureUrl(list.get(0).getUrl());
        }
        // 商品信息存储redis
        log.info("【中旅商城--商品详情--商品信息存储缓存】,入参为:{}", JSON.toJSONString(commodityInfo));
        redisTemplate.opsForValue().set(RedisConstants.GOODS_COMMODITY_INFO, JSON.toJSONString(commodityInfo));
        log.info("【中旅商城--商品详情--end】");
        // 增加足迹
        addUserFootPoint(commodityInfo, userId);
        return Result.success(commodityInfo);
    }

    @Override
    public Result<List<String>> recommend(String keyword) {
        log.info("【中旅商城--app获取关键字推荐--start】，入参为 -- keyword:{}", keyword);
        LocalDateTime now = LocalDateTime.now();

        Boolean bool = false;

        // 缓存更新时间判断
        if (hasKey(RedisConstants.GOODS_RECOMMEND_KEYWORD)) {
            LocalDateTime retTime = JSON.parseObject((String) redisTemplate.opsForValue().get(RedisConstants.GOODS_CACHE_UPDATE), LocalDateTime.class);
            bool = true;
            if (null != retTime) {
                boolean before = now.isBefore(retTime);
                if (!before) {
                    redisTemplate.opsForValue().set(RedisConstants.GOODS_CACHE_UPDATE, JSON.toJSONString(now));
                }
            }
        } else {
            redisTemplate.opsForValue().set(RedisConstants.GOODS_CACHE_UPDATE, JSON.toJSONString(now));
        }

        List<String> commodityKeyWords = new ArrayList<>();
        // 查询关键词列表
        // 缓存存在数据
        if (hasKey(RedisConstants.GOODS_RECOMMEND_KEYWORD)) {
            List<String> keyWordList = JSON.parseArray((String) redisTemplate.opsForValue().get(RedisConstants.GOODS_RECOMMEND_KEYWORD), String.class);
            if (bool) {
                // 查询最新的关键字
                commodityKeyWords = commodityKeyWordMapper.selectWordListByKeyword(keyword, now);
                if (keyWordList.size() > 0 && keyWordList != null) {
                    for (int i = 0; i < keyWordList.size(); i++) {
                        if (!commodityKeyWords.contains(keyWordList.get(i))) {
                            commodityKeyWords.add(keyWordList.get(i));
                        }
                    }
                }
            }
            redisTemplate.opsForValue().set(RedisConstants.GOODS_RECOMMEND_KEYWORD, JSON.toJSONString(commodityKeyWords));
            return Result.success(commodityKeyWords);
            // 缓存不存在数据
        } else {
            commodityKeyWords = commodityKeyWordMapper.selectAllList(keyword).stream().map(CommodityKeyWord::getWords).collect(Collectors.toList());
        }
        log.info("【中旅商城--app获取关键字推荐--redis存储】，入参为 -- commodityKeyWords:{}", JSON.toJSONString(commodityKeyWords));
        redisTemplate.opsForValue().set(RedisConstants.GOODS_RECOMMEND_KEYWORD, JSON.toJSONString(commodityKeyWords));
        log.info("【中旅商城--app获取关键字推荐--end】");
        return Result.success(commodityKeyWords);
    }

    @Override
    public Result<PageResponse<CommodityInfoResp>> keywordSearch(String keyword, Integer statusCode, Integer page, Integer size) {
        log.info("【中旅商城--app关键字搜索--start】，入参为 -- keyword:{},statusCode:{},page:{},size:{}", keyword, statusCode, page, size);
        if (null == page || null == size) {
            page = 1;
            size = 10;
        }
        if (StringUtils.isEmpty(keyword) || null == statusCode) {
            return Result.failed(SystemError.SYS_402);
        }
        List<CommodityInfoResp> commodityInfoResps = new ArrayList<>();
        // 构建DSL语句
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 构建bool - query
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (!"".equals(keyword) && null != keyword) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("commodityName", keyword));
        }
        // 默认排序,七天内销量
        if (statusCode == 1) {
            sourceBuilder.sort(new FieldSortBuilder("sales").order(SortOrder.DESC));
        }
        // 新品排序
        else if (statusCode == 2) {
            sourceBuilder.sort(new FieldSortBuilder("gmtModified").order(SortOrder.DESC));
        }
        // 价格排序
        else if (statusCode == 3) {
            sourceBuilder.sort(new FieldSortBuilder("commodityCosts.price").order(SortOrder.DESC));
        }
        // 价格排序(降序)
        else if (statusCode == 4) {
            sourceBuilder.sort(new FieldSortBuilder("commodityCosts.price").order(SortOrder.ASC));
        }// 新品排序（降序）
        else if (statusCode == 5) {
            sourceBuilder.sort(new FieldSortBuilder("gmtModified").order(SortOrder.ASC));
        }
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.GOODS_INDEX);
        searchRequest.source(sourceBuilder);
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            commodityInfoResps = buildCommodityInfoResp(searchResponse);
        } catch (IOException e) {
//            e.printStackTrace();
            log.error("【中旅商城--app关键字搜索--报错】-- 关键字搜索错误为:{}", e.getMessage());
        }
//        commodityInfoResps = search(keyword, commodityInfoResps);
        PageResponse<CommodityInfoResp> response = new PageResponse<CommodityInfoResp>(commodityInfoResps, page == 1, commodityInfoResps.size() <= (page * size), commodityInfoResps.size(), page, size);
        log.info("【中旅商城--app关键字搜索--end】");
        return Result.success(response);
    }

    /**
     * list对象模糊匹配
     *
     * @param name
     * @param list
     * @return
     */
    public List search(String name, List list) {
        List result = new ArrayList();
        Pattern pattern = Pattern.compile(name);
        for (int i = 0; i < list.size(); i++) {
            Matcher matcher = pattern.matcher(((CommodityInfoResp) list.get(i)).getCommodityName());
            if (matcher.matches()) {
                result.add(list.get(i));
            }
        }
        return result;
    }

    @Override
    public Result<List<CommodityInfoResp>> commodityRecommend(Integer type) {
        List<CommodityInfoResp> commodityInfoResps = new ArrayList<>();
        if (null == type) {
            return Result.failed(SystemError.SYS_402);
        }
        // 构建DSL语句
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 构建bool查询
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        // 构建查询条件
        switch (type) {
            // 新品
            case 1:
                // 推荐
            case 2:
                // 精品
            case 3:
                // 优惠
            case 4:
                // 推广产品
            case 5:
//                queryBuilder.must(QueryBuilders.matchQuery("commodityRecommends.recommendType", type));
                queryBuilder.must(QueryBuilders.nestedQuery("commodityRecommends", QueryBuilders.matchQuery("commodityRecommends.recommendType", type), ScoreMode.None));
                break;
            default:
                queryBuilder.must(QueryBuilders.matchAllQuery());
                break;
        }
        sourceBuilder.query(queryBuilder);
        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.GOODS_INDEX);
        searchRequest.source(sourceBuilder);
        try {
            SearchResponse search = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            commodityInfoResps = buildCommodityInfoResp(search);
        } catch (IOException e) {
            log.error("【商品推荐查询ES数据错误】- {}", e);
        }
        return Result.success(commodityInfoResps);
    }

    @Override
    public Result<List<String>> hotWrods() {
        List<String> strList = commodityHotWordMapper.findSevenDaySearchWords();
        return Result.success(strList);
    }

    @Override
    public Result<List<CommodityClassificationLevelTwoDTO>> twoLevelAndApp() {
        List<CommodityClassificationLevelTwoDTO> twoDTOS = new ArrayList<>();
        List<CommodityClassificationLevelTwoDTO> twoDTOList = new ArrayList<>();
        // 查缓存，有数据直接获取
        if (hasKey(RedisConstants.GOODS_HOME_CLASSIFICATION)) {
            String str = (String) redisTemplate.opsForValue().get(RedisConstants.GOODS_HOME_CLASSIFICATION);
            List<CommodityClassificationAllLevelListDTO> allLevelListDTOS = JSON.parseObject(str, new TypeReference<List<CommodityClassificationAllLevelListDTO>>() {
            });
            log.info("【中旅商城--首页展示--缓存查询二级菜单】，返参为：{}", JSON.toJSONString(allLevelListDTOS));
            for (CommodityClassificationAllLevelListDTO listDTO : allLevelListDTOS) {
                CommodityClassificationLevelTwoDTO twoDTO = EntityUtil.copy(listDTO, CommodityClassificationLevelTwoDTO.class);
                twoDTOList.add(twoDTO);
            }
            Collections.sort(twoDTOList, new Comparator<CommodityClassificationLevelTwoDTO>() {
                @Override
                public int compare(CommodityClassificationLevelTwoDTO o1, CommodityClassificationLevelTwoDTO o2) {
                    if (null != o1.getSort() && null != o2.getSort()) {
                        if (o1.getSort() > o2.getSort()) {
                            return 1;
                        }
                        if (o1.getSort() == o2.getSort()) {
                            return 0;
                        }
                    }
                    return -1;
                }
            });
            twoDTOS.addAll(twoDTOList);
            twoDTOList.clear();
            // 无数据，数据库查询后返回
        } else {
            // 查询父子级分类名称集合列表
            List<CommodityClassificationAllLevelListDTO> classificationByAllLevel = classificationService.findClassificationByAllLevel(null);
            log.info("【中旅商城--首页展示--数据库查询二级菜单】，返参为：{}", JSON.toJSONString(classificationByAllLevel));
            if (!CollectionUtils.isEmpty(classificationByAllLevel)) {
                for (CommodityClassificationAllLevelListDTO levelListDTO : classificationByAllLevel) {
                    if (null != levelListDTO.getLevelTwo()) {
                        for (CommodityClassificationLevelTwoDTO twoDTO : levelListDTO.getLevelTwo()) {
                            twoDTOList.add(twoDTO);
                        }
                        Collections.sort(twoDTOList, new Comparator<CommodityClassificationLevelTwoDTO>() {
                            @Override
                            public int compare(CommodityClassificationLevelTwoDTO o1, CommodityClassificationLevelTwoDTO o2) {
                                if (o1.getSort() > o2.getSort()) {
                                    return 1;
                                }
                                if (o1.getSort() == o2.getSort()) {
                                    return 0;
                                }
                                return -1;
                            }
                        });
                        twoDTOS.addAll(twoDTOList);
                        twoDTOList.clear();
                    }
                }
                // 上架redis
                redisTemplate.opsForValue().set(RedisConstants.GOODS_HOME_CLASSIFICATION, JSON.toJSONString(twoDTOS));
            }
        }
        return Result.success(twoDTOS);
    }

    @Override
    public Result<CommodityInfoRespDTO> indexList(Integer type, String code, Integer size) {
        log.info("【中旅商城--首页聚合查询--start】，入参为：type:{},code:{},size:{}", type, code, size);
        if (StringUtils.isEmpty(code)) {
            return Result.failed(SystemError.SYS_402);
        }
        CommodityInfoRespDTO commodityInfoRespDTO = new CommodityInfoRespDTO();
        try {
            // 获取首页banner列表
            Result<BannerPositionListDTO> bannerPositionByCode = bannerPositionService.getBannerPositionByCode("zldj_BANNER");
            log.info("【中旅商城--首页聚合查询--首页banner列表】，返参为：{}", JSON.toJSONString(bannerPositionByCode.getData()));
            commodityInfoRespDTO.setBannerDTOPageResponse(bannerPositionByCode.getData());
        } catch (Exception e) {
            log.error("【中旅商城--首页聚合查询--banner列表获取错误】,{}", e);
            commodityInfoRespDTO.setBannerDTOPageResponse(null);
        }

        try {
            // 获取商城C端二级菜单展示
            Result<List<CommodityClassificationLevelTwoDTO>> listResult = iCommodityHomeService.twoLevelAndApp();
            log.info("【中旅商城--首页聚合查询--二级菜单展示】，返参为：{}", JSON.toJSONString(listResult.getData()));
            List<CommodityClassificationLevelTwoDTO> all = new ArrayList<>();
            for (CommodityClassificationLevelTwoDTO resultDatum : listResult.getData()) {
                if (null != resultDatum && null != resultDatum.getIcon()) {
//                    List<ShoppingSpecialPageUrlDTO> list = JSON.parseArray(resultDatum.getIcon(), ShoppingSpecialPageUrlDTO.class);
                    resultDatum.setPictureUrl(resultDatum.getIcon());
                }
                all.add(resultDatum);
            }
            commodityInfoRespDTO.setCommodityClassificationLevelTwoDTOList(all);
        } catch (Exception e) {
            log.error("【中旅商城--首页聚合查询--二级菜单获取错误】,{}", e);
            commodityInfoRespDTO.setCommodityClassificationLevelTwoDTOList(null);
        }

        try {
            // 获取商城C端商品推荐
            Result<List<CommodityInfoResp>> result = iCommodityHomeService.commodityRecommend(type);
            log.info("【中旅商城--首页聚合查询--商品推荐】，返参为：{}", JSON.toJSONString(result.getData()));
            IPage<CommodityInfoResp> commodityInfoRespIPage = new Page<>();
            commodityInfoRespIPage.setRecords(result.getData());
            PageResponse<CommodityInfoResp> response = new PageResponse<>();
            response.setIsFirst(commodityInfoRespIPage.getCurrent() == 1);
            response.setIsLast(commodityInfoRespIPage.getTotal() <= (commodityInfoRespIPage.getCurrent() * commodityInfoRespIPage.getSize()));
            response.setTotal(commodityInfoRespIPage.getTotal());
            response.setPageSize(size);
            response.setPageNo(commodityInfoRespIPage.getCurrent());
            response.setRecords(result.getData());
            commodityInfoRespDTO.setCommodityInfoRespList(response);
        } catch (Exception e) {
            log.error("【中旅商城--首页聚合查询--商品推荐获取错误】,{}", e.getMessage());
            commodityInfoRespDTO.setCommodityInfoRespList(null);
        }

        try {
            // 获取商城专题读取
            Result<List<ShoppingSpecialPageDTO>> shoppingSpecial = iCommodityHomeService.getShoppingSpecial();
            log.info("【中旅商城--首页聚合查询--专题读取】，返参为：{}", JSON.toJSONString(shoppingSpecial.getData().subList(0, 4)));
            commodityInfoRespDTO.setShoppingSpecialPageDTOS(shoppingSpecial.getData().subList(0, 4));
        } catch (Exception e) {
            log.error("【中旅商城--首页聚合查询--商城专题获取错误】,{}", e.getMessage());
            commodityInfoRespDTO.setShoppingSpecialPageDTOS(null);
        }

        try {
            // 获取banner推荐
            Result<BannerPositionListDTO> bannerPositionById = bannerPositionService.getBannerPositionByCode("zldj_BANNER2");
            log.info("【中旅商城--首页聚合查询--banner推荐】，返参为：{}", JSON.toJSONString(bannerPositionById.getData()));
            BannerPositionListDTO data = bannerPositionById.getData();
            commodityInfoRespDTO.setRecommended(data);
        } catch (Exception e) {
            log.error("【中旅商城--首页聚合查询--banner推荐位查询失败】，错误为:{}", JSON.toJSONString(e.getMessage()));
            commodityInfoRespDTO.setRecommended(null);
        }
        log.info("【中旅商城--首页聚合查询--end】");
        return Result.success(commodityInfoRespDTO);
    }

    @Override
    public Result<PageResponse<CommodityInfoResp>> getCommodityAll(Integer page, Integer size, Integer statusCode) {
        log.info("【中旅商城--app获取全部分页--start】，入参为:page:{},size:{},statusCode:{}", page, size, statusCode);
        if (null == page) {
            page = 1;
        }
        if (null == size) {
            size = 10;
        }
        List<CommodityInfoResp> commodityInfoResps = new ArrayList<>();
        // 构建DSL语句
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 构建bool查询
        QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
        // 默认排序,七天内销量
        if (statusCode == 1) {
            sourceBuilder.sort(new FieldSortBuilder("sales").order(SortOrder.DESC));
        }
        // 新品排序
        else if (statusCode == 2) {
            sourceBuilder.sort(new FieldSortBuilder("gmtModified").order(SortOrder.DESC));
        }
        // 价格排序(升序)
        else if (statusCode == 3) {
            sourceBuilder.sort(new FieldSortBuilder("commodityCosts.costPrice").order(SortOrder.DESC));
        }// 价格排序(降序)
        else if (statusCode == 4) {
            sourceBuilder.sort(new FieldSortBuilder("commodityCosts.costPrice").order(SortOrder.ASC));
        }// 新品排序（降序）
        else if (statusCode == 5) {
            sourceBuilder.sort(new FieldSortBuilder("gmtModified").order(SortOrder.ASC));
        }
        sourceBuilder.from(page);
        sourceBuilder.size(size);
        sourceBuilder.query(queryBuilder);
        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.GOODS_INDEX);
        searchRequest.source(sourceBuilder);
        Long total = 0L;
        try {
            SearchResponse search = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            total = search.getHits().getTotalHits().value;
            commodityInfoResps = buildCommodityInfoResp(search);
        } catch (IOException e) {
            log.error("【中旅商城--app获取全部分页--商品查询ES数据错误】- {}", e.getMessage());
        }
        PageResponse<CommodityInfoResp> response = new PageResponse<CommodityInfoResp>(commodityInfoResps, page == 1, total <= (page * size), total, page, size);
        log.info("【中旅商城--app获取全部分页--end】,返参为：{}", JSON.toJSONString(response));
        return Result.success(response);
    }

    @Override
    public Result<RegionalFreightDTO> region(RegionalFreightReq req) {
        log.info("【中旅商城--查询地区运费模板--start】，入参为:{}", JSON.toJSONString(req));
        // 商品地区运费模板查询
//        QueryWrapper<RegionalFreight> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("template_id",req.getFreightTemplateId());
//        queryWrapper.eq("region_id",req.getRegionId());
        RegionalFreight regionalFreight = regionalFreightMapper.selectRegionalFreightByTemplateIdAndRegionId(req.getFreightTemplateId(), req.getRegionId());
        log.info("【中旅商城--查询地区运费模板--地区运费查询】，返参为:{}", JSON.toJSONString(regionalFreight));
        if (null != regionalFreight) {
            RegionalFreightDTO regionalFreightDTO = EntityUtil.copy(regionalFreight, RegionalFreightDTO.class);
            log.info("【中旅商城--查询地区运费模板--end】");
            return Result.success(regionalFreightDTO);
        }
        return Result.failed(SystemError.MALL_MERCHANDISE_23004);
    }

    /**
     * 构建商城检索条件
     *
     * @return
     */
    public SearchRequest buildRequestFrom(String keyword) {
        // 构建DSL语句
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 1.构建 bool query
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // must-模糊匹配
        if (!StringUtils.isEmpty(keyword)) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("commodityName", keyword));
            // 高亮
            HighlightBuilder builder = new HighlightBuilder();
            builder.field("title");
            builder.preTags("<b style='color:red'>");
            builder.postTags("</b>");
            sourceBuilder.highlighter(builder);
        }
        /*聚合分类*/
        NestedAggregationBuilder goodsTerm_agg = AggregationBuilders.nested(ElasticSearchConstant.GOODS_AGG, ElasticSearchConstant.GOODS_PATH);
        TermsAggregationBuilder goods_price_agg = AggregationBuilders.terms(ElasticSearchConstant.GOODS_PRICE_AGG).field(ElasticSearchConstant.GOODS_PRICE);
        goods_price_agg.subAggregation(AggregationBuilders.terms(ElasticSearchConstant.GOODS_MARKINGPRICE_AGG).field(ElasticSearchConstant.GOODS_MARKINGPRICE));
        goodsTerm_agg.subAggregation(goods_price_agg);
        sourceBuilder.aggregation(goodsTerm_agg);
        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.TRIP_INDEX).source(sourceBuilder);
        return searchRequest;
    }

    // 增加足迹
    private void addUserFootPoint(CommodityInfo details, Long userId) {
        try {
            if (userId != null) {
                UserFootPointReq req = new UserFootPointReq();
                req.setUserId(userId);
                req.setType(SystemBusinessType.COMMODITY.getCode());
                req.setTitle(details.getCommodityName());
                req.setContent(details.getCommodityDetails());
                req.setCurrencyId(com.ctshk.common.enums.Currency.HKD.getCode());
                req.setCurrency(Currency.HKD.getCurrency());
                req.setPrice(details.getCommodityCostListResp().get(0).getCostPrice());
                req.setCoverUrl(details.getCommodityCostListResp().get(0).getPictureUrl());
                req.setDetailId(details.getId());
                userFootPointService.add(req);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
